<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>声音属性调节演示</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft YaHei", "Segoe UI", sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            color: white;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
        }
        
        .container {
            max-width: 800px;
            width: 100%;
            background: rgba(0, 0, 0, 0.7);
            border-radius: 20px;
            padding: 30px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            margin-top: 20px;
        }
        
        h1 {
            text-align: center;
            margin-bottom: 10px;
            font-size: 2.2rem;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
        }
        
        .subtitle {
            text-align: center;
            margin-bottom: 30px;
            opacity: 0.9;
            font-size: 1.1rem;
        }
        
        .player-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-bottom: 30px;
        }
        
        .now-playing {
            margin: 15px 0;
            font-size: 1.2rem;
            background: rgba(255, 255, 255, 0.1);
            padding: 10px 20px;
            border-radius: 20px;
        }
        
        .controls {
            display: flex;
            gap: 15px;
            margin-bottom: 20px;
            flex-wrap: wrap;
            justify-content: center;
        }
        
        button {
            padding: 12px 20px;
            border: none;
            border-radius: 8px;
            background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
            color: white;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
            min-width: 100px;
        }
        
        button:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4);
        }
        
        button:active {
            transform: translateY(1px);
        }
        
        .play-btn {
            background: linear-gradient(135deg, #00b09b 0%, #96c93d 100%);
            padding: 15px 30px;
            font-size: 1.2rem;
        }
        
        .control-panel {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-top: 20px;
        }
        
        .control-group {
            background: rgba(255, 255, 255, 0.1);
            padding: 20px;
            border-radius: 15px;
            text-align: center;
        }
        
        h2 {
            margin-bottom: 15px;
            font-size: 1.4rem;
            color: #ffdd00;
        }
        
        .slider-container {
            margin: 15px 0;
        }
        
        .slider-label {
            display: flex;
            justify-content: space-between;
            margin-bottom: 8px;
            font-size: 0.9rem;
        }
        
        input[type="range"] {
            width: 100%;
            height: 10px;
            -webkit-appearance: none;
            appearance: none;
            background: linear-gradient(to right, #1a2a6c, #b21f1f, #fdbb2d);
            outline: none;
            border-radius: 5px;
        }
        
        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 22px;
            height: 22px;
            border-radius: 50%;
            background: #2575fc;
            cursor: pointer;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
        }
        
        .value-display {
            font-size: 1.1rem;
            font-weight: bold;
            margin-top: 8px;
            color: #fdbb2d;
        }
        
        .visualization {
            width: 100%;
            height: 150px;
            margin: 30px 0;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            overflow: hidden;
            border: 2px solid rgba(255, 255, 255, 0.1);
        }
        
        canvas {
            width: 100%;
            height: 100%;
        }
        
        .explanation {
            margin-top: 30px;
            padding: 20px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 15px;
            border-left: 4px solid #fdbb2d;
        }
        
        .explanation h2 {
            text-align: center;
            margin-bottom: 15px;
            color: #ffdd00;
        }
        
        .explanation p {
            margin-bottom: 12px;
            line-height: 1.6;
            font-size: 0.95rem;
        }
        
        .footer {
            margin-top: 30px;
            text-align: center;
            font-size: 0.9rem;
            opacity: 0.7;
        }
        
        @media (max-width: 600px) {
            .container {
                padding: 20px;
            }
            
            h1 {
                font-size: 1.8rem;
            }
            
            .controls {
                gap: 10px;
            }
            
            button {
                padding: 10px 15px;
                font-size: 0.9rem;
                min-width: 80px;
            }
            
            .play-btn {
                padding: 12px 25px;
                font-size: 1.1rem;
            }
            
            .control-panel {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <h1>声音属性调节演示</h1>
    <p class="subtitle">体验音调、响度和音色的变化 - 国内优化版</p>
    
    <div class="container">
        <div class="player-container">
            <div class="now-playing">🎵 当前播放: 示例音频</div>
            <div class="controls">
                <button class="play-btn" id="playBtn">▶️ 播放音乐</button>
                <button id="stopBtn">⏹️ 停止播放</button>
            </div>
            
            <div class="visualization">
                <canvas id="visualizer"></canvas>
            </div>
        </div>
        
        <div class="control-panel">
            <div class="control-group">
                <h2>🎵 音调控制</h2>
                <div class="slider-container">
                    <div class="slider-label">
                        <span>低音</span>
                        <span>音调</span>
                        <span>高音</span>
                    </div>
                    <input type="range" id="pitchSlider" min="-12" max="12" value="0" step="1">
                    <div class="value-display">当前: 0 半音</div>
                </div>
                <div class="controls">
                    <button id="pitchDown">🔽 音调减</button>
                    <button id="pitchUp">🔼 音调加</button>
                </div>
            </div>
            
            <div class="control-group">
                <h2>🔊 响度控制</h2>
                <div class="slider-container">
                    <div class="slider-label">
                        <span>轻声</span>
                        <span>响度</span>
                        <span>响亮</span>
                    </div>
                    <input type="range" id="volumeSlider" min="0" max="100" value="70" step="1">
                    <div class="value-display">当前: 70%</div>
                </div>
                <div class="controls">
                    <button id="volumeDown">🔽 响度减</button>
                    <button id="volumeUp">🔼 响度加</button>
                </div>
            </div>
            
            <div class="control-group">
                <h2>🎹 音色控制</h2>
                <div class="slider-container">
                    <div class="slider-label">
                        <span>柔和</span>
                        <span>音色</span>
                        <span>明亮</span>
                    </div>
                    <input type="range" id="timbreSlider" min="0" max="100" value="50" step="1">
                    <div class="value-display">当前: 中性</div>
                </div>
                <div class="controls">
                    <button id="timbreChange">🔄 切换音色</button>
                </div>
            </div>
        </div>
        
        <div class="explanation">
            <h2>📚 声音三要素说明</h2>
            <p><strong>🎵 音调</strong>：表示声音的高低，由频率决定。频率越高，音调越高。单位：赫兹(Hz)。</p>
            <p><strong>🔊 响度</strong>：表示声音的强弱，由振幅决定。振幅越大，声音越响。单位：分贝(dB)。</p>
            <p><strong>🎹 音色</strong>：表示声音的品质，由谐波成分决定。不同乐器演奏同一音符时音色不同。</p>
        </div>
        
        <div class="footer">
            <p>© 2023 声音属性演示 | 本地HTML文件 | 无需联网</p>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            let audioContext;
            let source;
            let gainNode;
            let filterNode;
            let isPlaying = false;
            const canvas = document.getElementById('visualizer');
            const canvasCtx = canvas.getContext('2d');
            
            // 初始化界面
            function init() {
                // 设置滑块事件
                document.getElementById('pitchSlider').addEventListener('input', updatePitch);
                document.getElementById('volumeSlider').addEventListener('input', updateVolume);
                document.getElementById('timbreSlider').addEventListener('input', updateTimbre);
                
                // 设置按钮事件
                document.getElementById('playBtn').addEventListener('click', togglePlay);
                document.getElementById('stopBtn').addEventListener('click', stopAudio);
                document.getElementById('pitchDown').addEventListener('click', () => adjustPitch(-1));
                document.getElementById('pitchUp').addEventListener('click', () => adjustPitch(1));
                document.getElementById('volumeDown').addEventListener('click', () => adjustVolume(-10));
                document.getElementById('volumeUp').addEventListener('click', () => adjustVolume(10));
                document.getElementById('timbreChange').addEventListener('click', changeTimbre);
                
                // 初始化Canvas
                resizeCanvas();
                window.addEventListener('resize', resizeCanvas);
                drawVisualization();
            }
            
            // 调整Canvas大小
            function resizeCanvas() {
                canvas.width = canvas.offsetWidth;
                canvas.height = canvas.offsetHeight;
            }
            
            // 初始化音频
            function setupAudio() {
                if (audioContext) return;
                
                // 创建音频上下文
                audioContext = new (window.AudioContext || window.webkitAudioContext)();
                
                // 创建振荡器
                source = audioContext.createOscillator();
                source.type = 'sine';
                source.frequency.setValueAtTime(440, audioContext.currentTime);
                
                // 创建增益节点（音量控制）
                gainNode = audioContext.createGain();
                
                // 创建滤波器（音色控制）
                filterNode = audioContext.createBiquadFilter();
                filterNode.type = 'lowpass';
                filterNode.frequency.setValueAtTime(1000, audioContext.currentTime);
                
                // 连接音频节点
                source.connect(filterNode);
                filterNode.connect(gainNode);
                gainNode.connect(audioContext.destination);
                
                // 设置初始音量
                gainNode.gain.setValueAtTime(0.7, audioContext.currentTime);
                
                // 启动振荡器（但立即停止）
                source.start();
                source.stop();
            }
            
            // 播放/暂停切换
            function togglePlay() {
                if (!audioContext) {
                    setupAudio();
                }
                
                if (isPlaying) {
                    // 停止播放
                    source.stop();
                    document.getElementById('playBtn').textContent = '▶️ 播放音乐';
                    isPlaying = false;
                } else {
                    // 重新创建振荡器
                    source = audioContext.createOscillator();
                    source.type = document.getElementById('timbreSlider').dataset.currentType || 'sine';
                    source.frequency.setValueAtTime(440 * Math.pow(2, document.getElementById('pitchSlider').value/12), audioContext.currentTime);
                    source.connect(filterNode);
                    
                    // 开始播放
                    source.start();
                    document.getElementById('playBtn').textContent = '⏸️ 暂停音乐';
                    isPlaying = true;
                    
                    // 开始可视化
                    visualize();
                }
            }
            
            // 停止音频
            function stopAudio() {
                if (source) {
                    source.stop();
                }
                document.getElementById('playBtn').textContent = '▶️ 播放音乐';
                isPlaying = false;
            }
            
            // 更新音调
            function updatePitch() {
                if (!source) return;
                
                const pitchValue = document.getElementById('pitchSlider').value;
                const frequency = 440 * Math.pow(2, pitchValue/12);
                source.frequency.setValueAtTime(frequency, audioContext.currentTime);
                
                document.querySelector('#pitchSlider + .value-display').textContent = `当前: ${pitchValue} 半音`;
            }
            
            // 调整音调
            function adjustPitch(change) {
                const slider = document.getElementById('pitchSlider');
                let newValue = parseInt(slider.value) + change;
                newValue = Math.max(parseInt(slider.min), Math.min(parseInt(slider.max), newValue));
                slider.value = newValue;
                updatePitch();
            }
            
            // 更新音量
            function updateVolume() {
                if (!gainNode) return;
                
                const volumeValue = document.getElementById('volumeSlider').value;
                gainNode.gain.setValueAtTime(volumeValue/100, audioContext.currentTime);
                
                document.querySelector('#volumeSlider + .value-display').textContent = `当前: ${volumeValue}%`;
            }
            
            // 调整音量
            function adjustVolume(change) {
                const slider = document.getElementById('volumeSlider');
                let newValue = parseInt(slider.value) + change;
                newValue = Math.max(parseInt(slider.min), Math.min(parseInt(slider.max), newValue));
                slider.value = newValue;
                updateVolume();
            }
            
            // 更新音色
            function updateTimbre() {
                if (!filterNode) return;
                
                const timbreValue = document.getElementById('timbreSlider').value;
                // 通过滤波器改变音色
                filterNode.frequency.setValueAtTime(timbreValue * 20, audioContext.currentTime);
                
                let timbreText;
                if (timbreValue < 20) timbreText = "非常柔和";
                else if (timbreValue < 40) timbreText = "柔和";
                else if (timbreValue < 60) timbreText = "中性";
                else if (timbreValue < 80) timbreText = "明亮";
                else timbreText = "非常明亮";
                
                document.querySelector('#timbreSlider + .value-display').textContent = `当前: ${timbreText}`;
            }
            
            // 切换音色
            function changeTimbre() {
                if (!source) return;
                
                // 切换振荡器类型
                const types = ['sine', 'square', 'sawtooth', 'triangle'];
                const currentType = source.type;
                const currentIndex = types.indexOf(currentType);
                const nextIndex = (currentIndex + 1) % types.length;
                
                source.type = types[nextIndex];
                document.getElementById('timbreSlider').dataset.currentType = types[nextIndex];
                
                // 更新显示
                const typeNames = {
                    'sine': '正弦波', 
                    'square': '方波', 
                    'sawtooth': '锯齿波', 
                    'triangle': '三角波'
                };
                document.querySelector('#timbreSlider + .value-display').textContent = `当前: ${typeNames[types[nextIndex]]}`;
            }
            
            // 绘制可视化
            function drawVisualization() {
                if (!isPlaying) {
                    canvasCtx.fillStyle = 'rgba(0, 0, 0, 0.5)';
                    canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
                    
                    canvasCtx.fillStyle = 'white';
                    canvasCtx.textAlign = 'center';
                    canvasCtx.font = '16px Microsoft YaHei';
                    canvasCtx.fillText('点击播放音乐开始可视化', canvas.width/2, canvas.height/2);
                }
                requestAnimationFrame(drawVisualization);
            }
            
            // 音频可视化
            function visualize() {
                if (!audioContext) return;
                
                const analyser = audioContext.createAnalyser();
                gainNode.connect(analyser);
                analyser.fftSize = 256;
                
                const bufferLength = analyser.frequencyBinCount;
                const dataArray = new Uint8Array(bufferLength);
                
                function draw() {
                    if (!isPlaying) return;
                    
                    requestAnimationFrame(draw);
                    
                    analyser.getByteFrequencyData(dataArray);
                    
                    canvasCtx.fillStyle = 'rgba(0, 0, 0, 0.5)';
                    canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
                    
                    const barWidth = (canvas.width / bufferLength) * 2.5;
                    let barHeight;
                    let x = 0;
                    
                    for(let i = 0; i < bufferLength; i++) {
                        barHeight = dataArray[i] / 2;
                        
                        // 创建渐变颜色
                        const gradient = canvasCtx.createLinearGradient(0, canvas.height - barHeight, 0, canvas.height);
                        gradient.addColorStop(0, '#ff6b6b');
                        gradient.addColorStop(0.5, '#4ecdc4');
                        gradient.addColorStop(1, '#45b7d1');
                        
                        canvasCtx.fillStyle = gradient;
                        canvasCtx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
                        
                        x += barWidth + 1;
                    }
                }
                
                draw();
            }
            
            // 初始化应用
            init();
        });
    </script>
</body>
</html>